package com.cnap.multiclouldmgmt.controller;

import com.alibaba.fastjson.JSONObject;
import com.cnap.multiclouldmgmt.model.AlgScheduleInfoV2Model;
import com.cnap.multiclouldmgmt.model.CommonResult;
import com.cnap.multiclouldmgmt.model.RepByPage;
import com.cnap.multiclouldmgmt.model.alg.AccountNameReqModel;
import com.cnap.multiclouldmgmt.model.enums.CloudVendorsEnum;
import com.cnap.multiclouldmgmt.model.enums.K8sStatusEnum;
import com.cnap.multiclouldmgmt.model.gpu.GpuClusterMonitorInfo;
import com.cnap.multiclouldmgmt.model.k8sModels.*;
import com.cnap.multiclouldmgmt.model.k8sMonitorModels.*;
import com.cnap.multiclouldmgmt.model.knowledge.CalCauseParam;
import com.cnap.multiclouldmgmt.model.knowledge.QueryCaseParam;
import com.cnap.multiclouldmgmt.model.knowledge.RootCaseVO;
import com.cnap.multiclouldmgmt.model.microSvc.MicroSvcDataSaveModel;
import com.cnap.multiclouldmgmt.model.microSvc.MicroSvcReqCostInfoModel;
import com.cnap.multiclouldmgmt.model.prometheusModels.PrometheusAlertModel;
import com.cnap.multiclouldmgmt.model.scale.CreateScalingDTO;
import com.cnap.multiclouldmgmt.model.vm.CheckDelVmModel;
import com.cnap.multiclouldmgmt.service.*;
import com.cnap.multiclouldmgmt.util.CnapCloudMgmtConstants;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 对接其他子系统，提供各个集群的信息
 * 提供包括监控信息等
 *
 * @author dyq
 */
@Api(tags = "混合云网管理-监控数据提供")
@RequestMapping(path = "/cnap/multicloudmgmt/v1/clusterInfo")
@RestController
@ResponseBody
public class CnapClusterInfoController {

    private final static Logger LOGGER = LoggerFactory.getLogger(CnapClusterInfoController.class);

    @Autowired
    private MultiCloudMgmtService multiCloudMgmtService;

    @Autowired
    private K8sClusterService k8sClusterService;

    @Autowired
    private AlgInfoService algInfoService;

    @Autowired
    private PrometheusService prometheusService;

    @Autowired
    private CacheService cacheService;

    @Autowired
    private MicroSvcInfoService microSvcInfoService;

    @Autowired
    private HealthService healthService;

    @Autowired
    private ScalingService scalingService;

    /**
     * 获取所有云供应商
     *
     * @param createUser 用户名
     * @return 云商列表
     */
    @ApiOperation(value = "3-1 获取所有的云供应商", httpMethod = "GET",
            notes = "")
    @RequestMapping(path = "/getAllCloudVendors", method = RequestMethod.GET)
    public CommonResult<List<String>> getAllCloudVendors(String createUser) {

        try {
            //createUser为空，就返回所有云商
            List<String> result = new ArrayList<>();
            if (StringUtils.isEmpty(createUser)) {
                for (CloudVendorsEnum enumObj : CloudVendorsEnum.values()) {
                    result.add(enumObj.getDescribe());
                }
            } else {

                //返回当前用户建立了集群的云商类型
                result = multiCloudMgmtService.getCloudVendorsByCreateUser(createUser);
            }

            return CommonResult.success(result);

        } catch (Exception e) {

            LOGGER.error("CnapClusterInfoController getAllCloudVendors error", e);

            return CommonResult.failed(e.getMessage());
        }
    }

    /**
     * 获取所有集群的相关信息
     *
     * @param cloudVendor 云商类型
     * @param clusterName 集群名称
     * @param createUser  创建用户
     * @return 集群信息列表
     */
    @ApiOperation(value = "3-2 获取集群的情况", httpMethod = "GET",
            notes = "")
    @RequestMapping(path = "/getClusterMonitorInfos", method = RequestMethod.GET)
    public CommonResult<List<K8sClusterMonitorModel>> getClusterMonitorInfos(String cloudVendor, String clusterName, String createUser) {

        try {

            /**
             * 根据云商，集群名，创建者获取集群的数量
             * 参数可以为空,表示不筛选，获取所有数据
             * 数字为空表示没有符合条件的集群
             */
            List<K8sClusterMonitorModel> result = new ArrayList<>();
            int num = multiCloudMgmtService.getK8sClusterNum(cloudVendor, clusterName, createUser);
            if (num == 0) {
                return CommonResult.success(result);
            }

            //按页返回集群基本信息
            RepByPage<K8sClusterModel> k8sClusterInfos =
                    multiCloudMgmtService.getK8sClusterInfos(cloudVendor, clusterName, num, 1, createUser);

            //将基本信息进行处理，获取集群的其他信息
            for (K8sClusterModel k8sClusterModel : k8sClusterInfos.getResult()) {

                K8sClusterMonitorModel k8sClusterMonitorModel = new K8sClusterMonitorModel();
                k8sClusterMonitorModel.setCloudVendor(k8sClusterModel.getCloudVendor());
                k8sClusterMonitorModel.setCreateTimeStr(k8sClusterModel.getCreateTimeStr());
                k8sClusterMonitorModel.setK8sClusterIp(k8sClusterModel.getK8sClusterIp());
                k8sClusterMonitorModel.setK8sClusterName(k8sClusterModel.getK8sClusterName());
                k8sClusterMonitorModel.setK8sClusterLocation(k8sClusterModel.getK8sClusterLocation());
                k8sClusterMonitorModel.setCreateUser(k8sClusterModel.getCreateUser());
                k8sClusterMonitorModel.setNodeMonitorModels(new ArrayList<>());
                k8sClusterMonitorModel.setStatus(k8sClusterModel.getStatus());
                //如果集群不是运行状态，所有数据设置为0
                if (!StringUtils.equals(k8sClusterModel.getStatus(), K8sStatusEnum.Running.getChineseDescribe())) {
                    k8sClusterMonitorModel.setTotalNodeNum(0);
                    k8sClusterMonitorModel.setNormalNodeNum(0);
                    k8sClusterMonitorModel.setTotalPodNum(0);
                    k8sClusterMonitorModel.setNormalPodNum(0);
                    k8sClusterMonitorModel.setCpuUseRate("0");
                    k8sClusterMonitorModel.setMemoryUseRate("0");
                    result.add(k8sClusterMonitorModel);
                    continue;
                }

                //获取某个集群中所有的节点数量,如果没有入参，就走缓存
                RepByPage<NodeModel> nodeModelRepByPage = new RepByPage<>();
                if (StringUtils.isEmpty(cloudVendor) && StringUtils.isEmpty(clusterName)) {

                    nodeModelRepByPage = cacheService.getK8sNodeInfoByClusterName(createUser, k8sClusterModel.getK8sClusterName());

                } else {

                    int nodeNum = k8sClusterService.getK8sClusterNodeNum(cloudVendor,
                            k8sClusterMonitorModel.getK8sClusterName());
                    nodeModelRepByPage = k8sClusterService.getK8sClusterNodeInfosByConditions(
                            cloudVendor, k8sClusterMonitorModel.getK8sClusterName(),
                            null, nodeNum, 1);
                }

                //所有节点累计统计数据
                //cpu的总量，n为单位
                long cpuTotalByN = 0L;
                //cpu使用量，n为单位 ，1核=1000*1000*1000n
                long cpuUseByN = 0L;
                //内存总量，ki为单位
                long memTotalByKi = 0L;
                //内存使用量，ki为单位
                long memUseByKi = 0L;
                //正常节点数量
                int normalNodeNum = 0;
                //所有pod数量
                int totalPodNum = 0;
                //正常pod数量
                int normalPodNum = 0;
                //disk数量
                int diskQuota = 0;
                //disk使用
                int diskUse = 0;

                if (nodeModelRepByPage.getResult() != null) {
                    for (NodeModel nodeModel : nodeModelRepByPage.getResult()) {

                        cpuTotalByN += nodeModel.getNodeCpuQuotaByN();
                        cpuUseByN += nodeModel.getNodeCpuUseByN();
                        memTotalByKi += nodeModel.getNodeMemQuotaByKi();
                        memUseByKi += nodeModel.getNodeMemUseNumByKi();
                        diskQuota += nodeModel.getNodeDiskQuota();
                        diskUse += nodeModel.getNodeDiskUseNum();

                        //节点状态ready，则为正常节点
                        if (StringUtils.equals(nodeModel.getStatus(), K8sStatusEnum.Ready.getDescribe())) {
                            normalNodeNum++;
                        }
                        totalPodNum += nodeModel.getNodeContainerUseNum();
                        normalPodNum += nodeModel.getNodeContainerNormalNum();

                        NodeMonitorModel nodeMonitorModel = new NodeMonitorModel();
                        nodeMonitorModel.setNodeIp(nodeModel.getNodeIp());
                        nodeMonitorModel.setNodeName(nodeModel.getNodeName());
                        nodeMonitorModel.setNormalPodNum(nodeModel.getNodeContainerNormalNum());
                        nodeMonitorModel.setTotalPodNum(nodeModel.getNodeContainerNormalNum());
                        nodeMonitorModel.setStatus(nodeModel.getStatus());
                        nodeMonitorModel.setPodModels(nodeModel.getPodModels());

                        k8sClusterMonitorModel.getNodeMonitorModels().add(nodeMonitorModel);
                    }
                }

                k8sClusterMonitorModel.setTotalNodeNum(nodeModelRepByPage.getTotalNum());
                k8sClusterMonitorModel.setNormalNodeNum(normalNodeNum);
                k8sClusterMonitorModel.setTotalPodNum(totalPodNum);
                k8sClusterMonitorModel.setNormalPodNum(normalPodNum);
                if (totalPodNum != 0) {
                    k8sClusterMonitorModel.setPodQuota(String.format("%.2f", (float) normalPodNum / CnapCloudMgmtConstants.NODE_POD_QUOTA));
                }
                //计算cpu使用率，保留两位小数
                //防止cpuTotalByN为0
                if (cpuTotalByN != 0L) {
                    k8sClusterMonitorModel.setCpuUseRate(String.format("%.2f", (float) cpuUseByN / cpuTotalByN));
                }
                //计算内存使用率，保留两位小数
                if (memTotalByKi != 0L) {
                    k8sClusterMonitorModel.setMemoryUseRate(String.format("%.2f", (float) memUseByKi / memTotalByKi));
                }
                //计算硬盘使用
                if (diskQuota != 0L) {
                    k8sClusterMonitorModel.setDiskUseRate(String.format("%.2f", (float) diskUse / diskQuota));
                }

                result.add(k8sClusterMonitorModel);
            }


            return CommonResult.success(result);

        } catch (Exception e) {

            LOGGER.error("CnapClusterInfoController getClusterMonitorInfos error clusterName={} createUser={}",
                    clusterName, createUser, e);

            return CommonResult.failed(e.getMessage());
        }
    }

    /**
     * 获取集群所有svc情况
     *
     * @param cloudVendor    云商类型
     * @param k8sClusterName 集群名称
     * @param createUser     创建用户
     * @return 集群svc信息列表
     */
    @ApiOperation(value = "3-3 获取svc情况", httpMethod = "GET",
            notes = "")
    @RequestMapping(path = "/getSvcMonitorInfo", method = RequestMethod.GET)
    public CommonResult<List<SvcMonitorModel>> getSvcMonitorInfo(String cloudVendor, String k8sClusterName, String createUser) {

        try {

            /**
             * 根据云商，集群名，创建者获取集群的数量
             * 参数可以为空,表示不筛选，获取所有数据
             * 数字为空表示没有符合条件的集群
             */

            int clusterNum = multiCloudMgmtService.getK8sClusterNum(cloudVendor, k8sClusterName, createUser);
            if (clusterNum == 0) {
                return CommonResult.success(new ArrayList<>());
            }

            //按页返回集群基本信息
            RepByPage<K8sClusterModel> k8sClusterModels =
                    multiCloudMgmtService.getK8sClusterInfos(cloudVendor, k8sClusterName, clusterNum, 1, createUser);

            List<SvcMonitorModel> result = new ArrayList<>();
            for (K8sClusterModel k8sClusterModel : k8sClusterModels.getResult()) {

                //集群状态不正常的，不查询svc情况
                if (!StringUtils.equals(k8sClusterModel.getStatus(), K8sStatusEnum.Running.getChineseDescribe())) {
                    continue;
                }

                //获取集群svc的数量
                int num = k8sClusterService.getAllSvcNum(k8sClusterModel.getCloudVendor(),
                        k8sClusterModel.getK8sClusterName());
                if (StringUtils.equals(k8sClusterModel.getK8sClusterName(), CnapCloudMgmtConstants.TEST_ADMIN)) {
                    num = 1;
                }
                if (num == 0) {
                    continue;
                }

                //获取所有svc的基本信息
                RepByPage<SvcModel> svcModels = k8sClusterService.getK8sClusterSvcs(
                        k8sClusterModel.getCloudVendor(), k8sClusterModel.getK8sClusterName(), null, num, 1);
                if (StringUtils.equals(k8sClusterModel.getK8sClusterName(), CnapCloudMgmtConstants.TEST_ADMIN)) {
                    svcModels = new RepByPage<>();
                    svcModels.setResult(new ArrayList<>());
                    svcModels.getResult().add(new SvcModel());
                }
                //临时结果，拿到所有svc的model
                List<SvcMonitorModel> tmpResult = new ArrayList<>();
                for (SvcModel svcModel : svcModels.getResult()) {

                    SvcMonitorModel svcMonitorModel = new SvcMonitorModel();
                    svcMonitorModel.setCloudVendor(svcModel.getCloudVendor());
                    svcMonitorModel.setK8sClusterName(svcModel.getK8sClusterName());
                    svcMonitorModel.setClusterIp(svcModel.getClusterIp());
                    svcMonitorModel.setCreateUser(svcModel.getCreateUser());

                    svcMonitorModel.setNamespace(svcModel.getNamespace());
                    svcMonitorModel.setSvcName(svcModel.getSvcName());
                    svcMonitorModel.setSeclectorMap(svcModel.getSeclectorMap());
                    svcMonitorModel.setStatus(svcModel.getStatus());

                    tmpResult.add(svcMonitorModel);

                }

                //获取svc的其他信息
                result.addAll(k8sClusterService.getSvcMonitorInfo(k8sClusterModel.getCloudVendor(),
                        k8sClusterModel.getK8sClusterName(), tmpResult));
            }

            return CommonResult.success(result);

        } catch (Exception e) {

            LOGGER.error("CnapClusterInfoController getSvcMonitorInfo error", e);

            return CommonResult.failed(e.getMessage());
        }
    }

    /**
     * 获取负载均衡算法部署所需要的值
     *
     * @param algReqModel 请求参数，主要是集群名称
     * @return 算法所需要的信息
     * 返回示例
     * "cpu_usage": [0.8,4.0], //CPU使用状况, [该节点当前cpu使用量,该节点cpu总量]，单位为核数
     * "memory_usage": [120,12288], //内存使用状况,[该节点当前内存使用量,总量]，单位为MB
     * "disk_throughput": [100, 1000], //磁盘吞吐量,[该节点当前占用读写速率，该节点磁盘总读写速率]，单位为MB/s
     * "disk_iops": [1200, 15000], //磁盘IOPS，[该节点当前占用读写次数，该节点磁盘秒均总读写次数]，单位次/s
     * "net_bandwidth": [1000,100000], //网络带宽，[该节点当前占用带宽，该节点网络总带宽]，单位bps
     * "delay":5, //节点网络时延
     * "loss_rate":0.05, //节点丢包率
     */
    @ApiOperation(value = "3-4 获取负载均衡算法部署所需要的值（集群级别）", httpMethod = "POST",
            notes = "")
    @RequestMapping(path = "/getLoadBalanceDeployAlgInfo", method = RequestMethod.POST)
    public CommonResult<List<NodeAlgInfoModel>> getLoadBalaceDeployAlgInfo(@RequestBody AlgReqModel algReqModel) {

        try {

            //请求中的集群名称为空，则直接返回
            List<NodeAlgInfoModel> result = new ArrayList<>();
            if ((algReqModel.getK8sClusterNames() == null)
                    || (algReqModel.getK8sClusterNames().isEmpty())) {
                return CommonResult.success(result);
            }

            //获取集群的相关信息
            return CommonResult.success(algInfoService.getLoadBalaceDeployAlgInfo(algReqModel));

        } catch (Exception e) {

            LOGGER.error("CnapClusterInfoController getLoadBalaceDeployAlgInfo error", e);

            return CommonResult.failed(e.getMessage());
        }
    }


    /**
     * 获取负载均衡算法调度所需要的值
     *
     * @param algReqModel 请求参数，主要是集群名称
     * @return 算法所需要的信息
     * 返回示例
     * "cpu_usage": [0.8, 4.0], //CPU使用状况, [该副本的cpu使用量,该副本cpu总量]，单位为核数
     * "memory_usage": [120, 12288], //内存使用状况,[该副本当前的内存使用量,该副本内存总量],单位为MB
     * "disk_throughput": [100, 1000], //磁盘吞吐量,[该副本当前的占用读写速率，该副本总读写速率]，单位为MB/s
     * "disk_iops": [1200, 15000], //磁盘IOPS，[该副本当前的占用读写次数，该副本秒均总读写次数]，单位次/s
     * "net_bandwidth": [1000, 100000], //网络带宽，[该副本当前的占用带宽，该副本网络总带宽]，单位bps
     */
    @ApiOperation(value = "3-5 获取负载均衡算法调度所需要的值（集群+副本级别）", httpMethod = "POST",
            notes = "")
    @RequestMapping(path = "/getLoadBalanceInvokeAlgInfo", method = RequestMethod.POST)
    public CommonResult<List<NodeAlgInfoModel>> getLoadBalanceInvokeAlgInfo(@RequestBody AlgReqModel algReqModel) {

        try {

            //请求中的集群名称为空，则直接返回
            List<NodeAlgInfoModel> result = new ArrayList<>();
            if ((algReqModel.getK8sClusterNames() == null)
                    || (algReqModel.getK8sClusterNames().isEmpty())) {
                return CommonResult.success(result);
            }

            //获取集群的相关信息
            return CommonResult.success(algInfoService.getLoadBalanceInvokeAlgInfo(algReqModel));

        } catch (Exception e) {

            LOGGER.error("CnapClusterInfoController getLoadBalaceInvokeAlgInfo error workdLoadName={}", algReqModel.getWorkdLoadName(), e);

            return CommonResult.failed(e.getMessage());
        }
    }

    /**
     * 获取某个集群的事件，按时间倒序
     *
     * @param k8sClusterName 集群名称
     * @param userName       用户名称
     * @param beginTime      查询开始时间
     * @param reason         筛选原因
     * @param pageSize       分页大小
     * @param pageNo         页数
     * @return 按页返回集群事件
     */
    @ApiOperation(value = "3-6 获取某个集群的事件，按时间倒序", httpMethod = "GET",
            notes = "")
    @RequestMapping(path = "/getK8sClusterEvents", method = RequestMethod.GET)
    public CommonResult<RepByPage<EventModel>> getK8sClusterEvents(String k8sClusterName, String userName, String beginTime, String reason,
                                                                   int pageSize, int pageNo,String endTime,String cloudVendor) {

        try {

            //按条件返回所有事件
            return CommonResult.success(k8sClusterService.getK8sClusterEvents(k8sClusterName, userName, beginTime,
                    reason, pageSize, pageNo,endTime));

        } catch (Exception e) {

            LOGGER.error("CnapClusterInfoController getK8sClusterEvents error k8sClusterName={}", k8sClusterName, e);

            return CommonResult.failed(e.getMessage());
        }

    }

    /**
     * 查询prometheus的时间段内的事件
     *
     * @param pSql      Prometheus查询语句
     * @param userName  用户名
     * @param beginDate 开始时间
     * @param endDate   结束时间
     * @return Prometheus查询结果
     */
    @ApiOperation(value = "3-7 查询prometheus的时间段内的事件", httpMethod = "GET",
            notes = "")
    @RequestMapping(path = "/getPrometheusRangeData", method = RequestMethod.GET)
    public CommonResult<List<PrometheusAlertModel>> getPrometheusRangeData(String pSql, String userName,
                                                                           String beginDate, String endDate) {

        try {

            //查询指定时间段内的性能数据
            return CommonResult.success(prometheusService.getPrometheusRangeData(pSql, userName, beginDate, endDate));

        } catch (Exception e) {

            LOGGER.error("CnapClusterInfoController getPrometheusRangeData error pSql={}", pSql, e);

            return CommonResult.failed(e.getMessage());
        }

    }

    /**
     * 获取node的情况
     *
     * @param cloudVendor    云商名称
     * @param k8sClusterName 集群名称
     * @param nodeName       节点名称
     * @param createUser     用户名
     * @param pageSize       分页大小
     * @param pageNo         页数
     * @param appType        筛选节点标签
     * @return 节点的各项信息
     */
    @ApiOperation(value = "3-8 获取node的情况", httpMethod = "GET",
            notes = "")
    @RequestMapping(path = "/getNodeMonitorInfo", method = RequestMethod.GET)
    public CommonResult<RepByPage<NodeModel>> getNodeMonitorInfo(String cloudVendor, String k8sClusterName, String nodeName, String createUser,
                                                                 int pageSize, int pageNo, String appType) {


        try {

            //如果cluster name为空，从缓存中获取信息
            if (StringUtils.isEmpty(cloudVendor)
                    || StringUtils.isEmpty(k8sClusterName)) {
                //缓存获取
                List<RepByPage<NodeModel>> nodeInfos = cacheService.getK8sNodeInfo(createUser);

                //按条件组装
                RepByPage<NodeModel> result = new RepByPage<>();
                result.setPageNo(pageNo);
                result.setPageSize(pageSize);
                result.setTotalNum(0);
                result.setResult(new ArrayList<>());

                if ((nodeInfos == null) || (nodeInfos.isEmpty())) {
                    return CommonResult.success(result);
                }

                //获取不同集群的node
                for (RepByPage<NodeModel> nodeModelRepByPage : nodeInfos) {

                    List<NodeModel> nodeModels = new ArrayList<>();

                    for (NodeModel nodeModel : nodeModelRepByPage.getResult()) {

                        //查看是否有筛选条件
                        boolean addFlag = true;

                        if (StringUtils.isNotEmpty(cloudVendor)) {
                            if (!StringUtils.equals(nodeModel.getCloudVendor(), cloudVendor)) {
                                addFlag = false;
                            }
                        }

                        if (StringUtils.isNotEmpty(k8sClusterName)) {
                            if (!StringUtils.equals(nodeModel.getK8sClusterName(), k8sClusterName)) {
                                addFlag = false;
                            }
                        }

                        if (addFlag) {
                            nodeModels.add(nodeModel);
                        }
                    }

                    //统计总数
                    result.setTotalNum(result.getTotalNum() + nodeModels.size());
                    result.getResult().addAll(nodeModels);
                }

                //做分页
                int beginIndex = 0;
                int endIndex = result.getResult().size();
                if (((pageNo - 1) * pageSize) > endIndex) {
                    result.setResult(new ArrayList<>());

                } else {
                    beginIndex = (pageNo - 1) * pageSize;
                    endIndex = Math.min((pageNo * pageSize), endIndex);
                    result.setResult(result.getResult().subList(beginIndex, endIndex));
                }
                return CommonResult.success(result);
            }

            /**
             * 如果appType不为空
             * 则查找节点标签Key为NODE_APP_TYPE_LABEL + appType，值为appType的节点
             */
            String labelKey = null;
            if (StringUtils.isNotEmpty(appType)) {
                labelKey = CnapCloudMgmtConstants.NODE_APP_TYPE_LABEL + appType.toLowerCase();
            }

            //根据条件返回所有节点信息
            return CommonResult.success(
                    k8sClusterService.getK8sClusterNodeInfosByConditions(cloudVendor, k8sClusterName, nodeName,
                            "", pageSize, pageNo, labelKey, appType));

        } catch (Exception e) {

            LOGGER.error("CnapClusterInfoController getNodeMonitorInfo error k8sClusterName={}", k8sClusterName, e);

            return CommonResult.failed(e.getMessage());
        }


    }

    /**
     * 获取pod的情况
     *
     * @param cloudVendor    云商名称
     * @param k8sClusterName 集群名称
     * @param nodeName       节点名称
     * @param createUser     用户名
     * @param pageSize       分页大小
     * @param pageNo         页数
     * @param keyword        关键字筛选
     * @return pod的各项信息
     */
    @ApiOperation(value = "3-9 获取pod的情况", httpMethod = "GET",
            notes = "")
    @RequestMapping(path = "/getPodMonitorInfo", method = RequestMethod.GET)
    public CommonResult<RepByPage<PodModel>> getPodMonitorInfo(String cloudVendor, String k8sClusterName, String nodeName,
                                                               String createUser, String keyword,
                                                               int pageSize, int pageNo) {


        try {


            if (StringUtils.isEmpty(cloudVendor)
                    || StringUtils.isEmpty(k8sClusterName)) {

                //缓存获取
                List<RepByPage<PodModel>> podInfos = cacheService.getK8sPodInfo(createUser);

                //按条件组装
                RepByPage<PodModel> result = new RepByPage<>();
                result.setPageNo(pageNo);
                result.setPageSize(pageSize);
                result.setTotalNum(0);
                result.setResult(new ArrayList<>());

                if ((podInfos == null) || (podInfos.isEmpty())) {
                    return CommonResult.success(result);
                }

                //获取不同集群的node
                for (RepByPage<PodModel> podModelRepByPage : podInfos) {

                    List<PodModel> podModels = new ArrayList<>();

                    for (PodModel podModel : podModelRepByPage.getResult()) {

                        //查看是否有筛选条件
                        boolean addFlag = true;

                        if (StringUtils.isNotEmpty(cloudVendor)) {
                            if (!StringUtils.equals(podModel.getCloudVendor(), cloudVendor)) {
                                addFlag = false;
                            }
                        }

                        if (StringUtils.isNotEmpty(k8sClusterName)) {
                            if (!StringUtils.equals(podModel.getK8sClusterName(), k8sClusterName)) {
                                addFlag = false;
                            }
                        }

                        if (StringUtils.isNotEmpty(keyword)) {
                            if (!StringUtils.containsIgnoreCase(podModel.getPodName(), keyword)) {
                                addFlag = false;
                            }
                        }

                        if (addFlag) {
                            podModels.add(podModel);
                        }
                    }

                    //统计总数
                    result.setTotalNum(result.getTotalNum() + podModels.size());
                    result.getResult().addAll(podModels);
                }

                //做分页
                int beginIndex = 0;
                int endIndex = result.getResult().size();
                if (((pageNo - 1) * pageSize) > endIndex) {
                    result.setResult(new ArrayList<>());

                } else {
                    beginIndex = (pageNo - 1) * pageSize;
                    endIndex = Math.min((pageNo * pageSize), endIndex);
                    result.setResult(result.getResult().subList(beginIndex, endIndex));
                }
                return CommonResult.success(result);
            }

            //根据条件返回pod的数据
            return CommonResult.success(
                    k8sClusterService.getK8sClusterPods(cloudVendor, k8sClusterName, keyword, null,
                            null, null, nodeName, pageSize, pageNo));

        } catch (Exception e) {

            LOGGER.error("CnapClusterInfoController getPodMonitorInfo error k8sClusterName={}", k8sClusterName, e);

            return CommonResult.failed(e.getMessage());
        }

    }

    /**
     * 获取动态扩缩容接口需要的值
     *
     * @param algReqModel 请求参数，主要是集群名称
     * @return 算法所需要的信息
     * 返回示例
     * "cpu_usage": [0.8, 4.0], //CPU使用状况, [该副本的cpu使用量,该副本cpu总量]，单位为核数
     * "memory_usage": [120, 12288], //内存使用状况,[该副本当前的内存使用量,该副本内存总量],单位为MB
     * "disk_throughput": [100, 1000], //磁盘吞吐量,[该副本当前的占用读写速率，该副本总读写速率]，单位为MB/s
     * "disk_iops": [1200, 15000], //磁盘IOPS，[该副本当前的占用读写次数，该副本秒均总读写次数]，单位次/s
     * "net_bandwidth": [1000, 100000], //网络带宽，[该副本当前的占用带宽，该副本网络总带宽]，单位bps
     */
    @ApiOperation(value = "3-10 获取动态扩缩容接口需要的值", httpMethod = "POST",
            notes = "")
    @RequestMapping(path = "/getHpaAlgInfo", method = RequestMethod.POST)
    public CommonResult<List<K8sClusterAlgInfoModel>> getHpaAlgInfo(@RequestBody AlgReqModel algReqModel) {

        try {

            //请求中的集群名称为空，则直接返回
            List<K8sClusterAlgInfoModel> result = new ArrayList<>();
            if ((algReqModel.getK8sClusterNames() == null) || (algReqModel.getK8sClusterNames().isEmpty())) {
                return CommonResult.success(result);
            }

            //获取动态扩缩容接口需要的值
            return CommonResult.success(algInfoService.getHpaAlgInfo(algReqModel));

        } catch (Exception e) {

            LOGGER.error("CnapClusterInfoController getHpaAlgInfo error", e);

            return CommonResult.failed(e.getMessage());
        }
    }

    /**
     * 根据条件获取集群列表
     *
     * @param cloudVendor    云商名称
     * @param k8sClusterName 集群名称
     * @param userName       用户名
     * @param pageSize       分页大小
     * @param pageNo         页数
     * @return 集群的各项信息
     */
    @ApiOperation(value = "3-11 根据条件获取集群列表", httpMethod = "GET",
            notes = "入参云供应商cloudVendor，选择集群的名称k8sClusterName")
    @RequestMapping(path = "/getK8sClusterInfos", method = RequestMethod.GET)
    public CommonResult<RepByPage<K8sClusterModel>> getK8sClusterInfos(String cloudVendor, String k8sClusterName, String userName,
                                                                       int pageSize, int pageNo) {

        try {

            return CommonResult.success(
                    multiCloudMgmtService.getK8sClusterInfos(cloudVendor, k8sClusterName, pageSize, pageNo, userName));

        } catch (Exception e) {

            LOGGER.error("CnapClusterInfoController getK8sClusterInfos error pageNo={}", pageNo, e);

            return CommonResult.failed(e.getMessage());
        }
    }

    /**
     * 获取一个svc相关联的所有的pod和workload情况（为了flink状态服务）
     *
     * @param k8sClusterName 集群名
     * @param namespace      命名空间
     * @param svcName        服务名称
     * @param framework      采用架构名称
     * @return 返回服务的信息
     */
    @ApiOperation(value = "3-11 获取一个svc相关联的所有的pod和workload情况（为了flink或者spark状态服务）", httpMethod = "GET",
            notes = "入参，集群的名称k8sClusterName，命名空间namespace，应用名称svcName")
    @RequestMapping(path = "/getSvcPodFlinks", method = RequestMethod.GET)
    public CommonResult<SvcMonitorModel> getSvcPodFlinks(String k8sClusterName, String namespace, String svcName, String framework) {

        try {

            //默认框架是flink，除非framework写了spark
            if (StringUtils.equals(framework, "spark")) {

                //查询spark服务的相关情况
                return CommonResult.success(k8sClusterService.getSvcPodSpark(k8sClusterName, namespace, svcName));
            }

            //查询flink服务的情况
            return CommonResult.success(k8sClusterService.getSvcPodFlinks(k8sClusterName, namespace, svcName));

        } catch (Exception e) {

            LOGGER.error("CnapClusterInfoController getSvcPodFlinks error pageNo={}", svcName, e);

            return CommonResult.failed(e.getMessage());
        }
    }

    /**
     * 获取成本最优算法的相关值
     *
     * @param algReqModel 请求参数，主要是集群名称
     * @return 算法所需要的信息
     * # 集群名字-唯一标识集群
     * "name": "cluster1",
     * # 集群id
     * "id": 1,
     * # 集群内工作节点的总数,也即下面所有类型的节点数量之和
     * "num_workers": 15,
     * # 集群内CPU类型节点的总数
     * "num_GPU_workers": 3,
     * # 集群内FPGA类型节点的总数
     * "num_FPGA_workers": 3,
     * # 集群内CPU类型节点的总数
     * "num_CPU_workers": 9,
     * # 集群内剩余可用的CPU核数
     * "residual_vCPU": 65.4,
     * # 集群内剩余可用的运行内存数
     * "residual_RAM": 123.2,
     * # 集群内剩余可用的GPU块数
     * "residual_GPU": 12,
     * # 集群内剩余可用的FPGA块数
     * "residual_FPGA": 3,
     * # 集群内剩余可用的块存储容量
     * "residual_BS": 1024,
     * # 集群内剩余可用的文件存储容量
     * "residual_FS": 512,
     * # 集群出口的剩余带宽
     * "residual_NR": 100,
     * # 集群内CPU节点的每小时平均成本， 单位：元/小时
     * "price_per_CPU_worker": 2,
     * # 集群内GPU节点的每小时平均成本， 单位：元/小时
     * "price_per_GPU_worker": 10,
     * # 集群内FPGA节点的每小时平均成本， 单位：元/小时
     * "price_per_FPGA_worker": 9,
     * # 集群内块存储资源的每小时平均成本， 单位：元/GB小时
     * "price_per_BS": 0.5,
     * # 集群内文件存储资源的每小时平均成本， 单位：元/GB小时
     * "price_per_FS": 0.55,
     * # 集群公网出口网络资源的计费方式，按流量计费或按固定带宽计费， 单位：字符串 可选"Flow" 或 "Bandwidth"
     * "price_model_NR": "Flow",
     * # 集群公网出口网络资源的成本，若为按流量计费，则单位为 元/GB/小时；若为按固定带宽计费，则单位为 元/Mbps/小时
     * "price_per_NR": 0.02,
     */
    @ApiOperation(value = "3-12 获取成本最优算法的相关值", httpMethod = "POST",
            notes = "")
    @RequestMapping(path = "/getCostOptAlgInfo", method = RequestMethod.POST)
    public CommonResult<List<K8sClusterCostAlgInfoModel>> getCostOptAlgInfo(@RequestBody AlgReqModel algReqModel) {

        try {

            //请求中的集群名称为空，则直接返回
            List<K8sClusterCostAlgInfoModel> result = new ArrayList<>();
            if ((algReqModel.getK8sClusterNames() == null) || (algReqModel.getK8sClusterNames().isEmpty())) {
                return CommonResult.success(result);
            }

            //获取成本相关的信息
            return CommonResult.success(algInfoService.getCostAlgInfo(algReqModel));

        } catch (Exception e) {

            LOGGER.error("CnapClusterInfoController getCostOptAlgInfo error", e);

            return CommonResult.failed(e.getMessage());
        }
    }

    /**
     * 获取一个svc相关联的所有的pod和workload情况（为了spark的状态）
     *
     * @param k8sClusterName 集群名
     * @param namespace      命名空间
     * @param svcName        服务名称
     * @return 返回服务的信息
     */
    @ApiOperation(value = "3-13 获取一个svc相关联的所有的pod和workload情况（为了spark的状态）", httpMethod = "GET",
            notes = "入参，集群的名称k8sClusterName，命名空间namespace，应用名称svcName")
    @RequestMapping(path = "/getSvcPodSpark", method = RequestMethod.GET)
    public CommonResult<SvcMonitorModel> getSvcPodSpark(String k8sClusterName, String namespace, String svcName) {

        try {

            //返回spark服务相关情况
            return CommonResult.success(k8sClusterService.getSvcPodSpark(k8sClusterName, namespace, svcName));

        } catch (Exception e) {

            LOGGER.error("CnapClusterInfoController getSvcPodFlinks error pageNo={}", svcName, e);

            return CommonResult.failed(e.getMessage());
        }
    }

    /**
     * 获取动态扩展算法调度所需要的值（集群+副本级别）
     *
     * @param algReqModel 请求参数，主要是集群名称
     * @return 算法所需要的信息
     * "cpu_usage": [0.8, 4.0], //CPU使用状况, [该副本的cpu使用量,该副本cpu总量]，单位为核数
     * "memory_usage": [120, 12288], //内存使用状况,[该副本当前的内存使用量,该副本内存总量],单位为MB
     * "disk_throughput": [100, 1000], //磁盘吞吐量,[该副本当前的占用读写速率，该副本总读写速率]，单位为MB/s
     * "disk_iops": [1200, 15000], //磁盘IOPS，[该副本当前的占用读写次数，该副本秒均总读写次数]，单位次/s
     * "net_bandwidth": [1000, 100000], //网络带宽，[该副本当前的占用带宽，该副本网络总带宽]，单位bps
     */
    @ApiOperation(value = "3-14 获取动态扩展算法调度所需要的值（集群+副本级别）", httpMethod = "POST",
            notes = "")
    @RequestMapping(path = "/getDynamicExpansionAlgInfo", method = RequestMethod.POST)
    public CommonResult<List<DynamicExpansionSvcAlgModel>> getDynamicExpansionAlgInfo(@RequestBody AlgReqModel algReqModel) {

        try {

            //如果集群名称为空，则直接返回
            List<DynamicExpansionSvcAlgModel> result = new ArrayList<>();
            if ((algReqModel.getK8sClusterNames() == null)
                    || (algReqModel.getK8sClusterNames().isEmpty())) {
                return CommonResult.success(result);
            }

            //动态扩展算法的信息
            return CommonResult.success(algInfoService.getDynamicExpansionAlgInfo(algReqModel));

        } catch (Exception e) {

            LOGGER.error("CnapClusterInfoController getDynamicExpansionAlgInfo error svcName={} clusterName={}",
                    algReqModel.getSvcName(), JSONObject.toJSONString(algReqModel.getK8sClusterNames()), e);

            return CommonResult.failed(e.getMessage());
        }
    }

    /**
     * 检查vm能不能删除
     *
     * @param checkDelVmModel 主要是vmId
     *                        vmId正在使用就不能删除
     * @return
     */
    @ApiOperation(value = "3-15 检查vm能不能删除", httpMethod = "POST",
            notes = "")
    @RequestMapping(path = "/checkVmDel", method = RequestMethod.POST)
    public CommonResult<CheckDelVmModel> checkVmDel(@RequestBody CheckDelVmModel checkDelVmModel) {

        try {
            if (StringUtils.isEmpty(checkDelVmModel.getCloudType())
                    || StringUtils.isEmpty(checkDelVmModel.getVmId())) {
                return CommonResult.failed("参数未填写");
            }

            //是否能删除
            return CommonResult.success(multiCloudMgmtService.checkVmDelResult(checkDelVmModel));

        } catch (Exception e) {

            LOGGER.error("CnapClusterInfoController checkVmDel error vmId={}", checkDelVmModel.getVmId(), e);

            return CommonResult.failed(e.getMessage());
        }
    }

    @ApiOperation(value = "3-16 获取微服务相关的性能指标", httpMethod = "POST",
            notes = "")
    @RequestMapping(path = "/getMicroSvcInfo", method = RequestMethod.POST)
    public CommonResult<MicroSvcDataSaveModel> getMicroSvcInfo(@RequestBody MicroSvcDataSaveModel microSvcDataSaveModel) {

        try {

            MicroSvcDataSaveModel result = microSvcInfoService.getMicroSvcDataNow(microSvcDataSaveModel.getK8sClusterName(),
                    microSvcDataSaveModel.getMicroSvcId());
            return CommonResult.success(result);

        } catch (Exception e) {

            LOGGER.error("CnapClusterInfoController getMicroSvcInfo error id={}", microSvcDataSaveModel.getMicroSvcId(), e);

            return CommonResult.failed(e.getMessage());
        }
    }

    @ApiOperation(value = "3-17 获取某个微服务最近一小时的平均响应时间", httpMethod = "POST",
            notes = "")
    @RequestMapping(path = "/getMicroSvcReqCostLastHour", method = RequestMethod.POST)
    public CommonResult<MicroSvcReqCostInfoModel> getMicroSvcReqCostLastHour(@RequestBody MicroSvcReqCostInfoModel microSvcReqCostInfoModel) {

        try {

            microSvcInfoService.getMicroSvcReqCostLastHour(microSvcReqCostInfoModel.getMicroSvcId());
            return CommonResult.success(microSvcReqCostInfoModel);

        } catch (Exception e) {

            LOGGER.error("CnapClusterInfoController getMicroSvcReqCostLastHour error id={}", microSvcReqCostInfoModel.getMicroSvcId(), e);

            return CommonResult.failed(e.getMessage());
        }
    }

    @ApiOperation(value = "3-18 计算根因", httpMethod = "POST", notes = "计算根因")
    @PostMapping("/cause/cal")
    public CommonResult<String> calRootCause(@RequestBody CalCauseParam calCauseParam) {
        healthService.calRootCause(calCauseParam);
        return CommonResult.success("success");
    }

    @ApiOperation(value = "3-19 查询根因", httpMethod = "POST", notes = "查询根因")
    @PostMapping("/cause/list")
    public CommonResult<RepByPage<RootCaseVO>> listRootCases(@RequestBody QueryCaseParam queryCaseParam) {
        RepByPage<RootCaseVO> result = healthService.findByPage(queryCaseParam);
        return CommonResult.success(result);
    }

    @ApiOperation(value = "3-20 删除根因", httpMethod = "DELETE", notes = "删除根因")
    @DeleteMapping("/cause/delete/{causeId}")
    public CommonResult<String> deleteRootCauseById(@PathVariable("causeId") String causeId) {
        boolean result = healthService.deleteRootCauseById(causeId);
        return result ? CommonResult.success("success") : CommonResult.failed("fail");
    }

    @ApiOperation(value = "3-21 获取负载均衡算法部署所需要的值（集群级别）", httpMethod = "POST",
            notes = "")
    @RequestMapping(path = "/getClusterLoadInfoV2", method = RequestMethod.POST)
    public CommonResult<List<AlgClusterInfoV2Model>> getClusterLoadInfoV2(@RequestBody AlgReqModel algReqModel) {

        try {

            //请求中的集群名称为空，则直接返回
            List<AlgClusterInfoV2Model> result = new ArrayList<>();
            if ((algReqModel.getK8sClusterNames() == null)
                    || (algReqModel.getK8sClusterNames().isEmpty())) {
                return CommonResult.success(result);
            }

            //获取集群的相关信息
            return CommonResult.success(algInfoService.getDeployAlgInfoV2(algReqModel));

        } catch (Exception e) {

            LOGGER.error("CnapClusterInfoController getLoadBalaceDeployAlgInfo error", e);

            return CommonResult.failed(e.getMessage());
        }
    }

    @ApiOperation(value = "3-22 获取调度负载均衡算法部署所需要的值（集群级别）", httpMethod = "POST",
            notes = "")
    @RequestMapping(path = "/getClusterScheduleInfoV2", method = RequestMethod.POST)
    public CommonResult<List<AlgScheduleInfoV2Model>> getClusterScheduleInfoV2(@RequestBody AlgReqModel algReqModel) {

        try {

            //请求中的集群名称为空，则直接返回
            List<AlgScheduleInfoV2Model> result = new ArrayList<>();
            if ((algReqModel.getK8sClusterNames() == null)
                    || (algReqModel.getK8sClusterNames().isEmpty())) {
                return CommonResult.success(result);
            }

            //获取集群的相关信息
            return CommonResult.success(algInfoService.getScheduleAlgInfoV2(algReqModel));

        } catch (Exception e) {

            LOGGER.error("CnapClusterInfoController getLoadBalaceDeployAlgInfo error", e);

            return CommonResult.failed(e.getMessage());
        }
    }

    @ApiOperation(value = "3-23 创建默认伸缩配置", httpMethod = "POST", notes = "创建默认伸缩配置")
    @PostMapping("/create-default")
    public CommonResult<String> updateScalingPolicy(@RequestBody List<CreateScalingDTO> dtos) {
        scalingService.updateScalingPolicy(dtos);
        return CommonResult.success("success");
    }


    /**
     * 获取gpu top5的集群
     * @return 集群信息列表
     */
    @ApiOperation(value = "3-24 获取gpu top5的集群", httpMethod = "GET",
            notes = "")
    @RequestMapping(path = "/getTop5GpuClusterInfo", method = RequestMethod.GET)
    public CommonResult<List<GpuClusterMonitorInfo>> getClusterMonitorInfos() {

        try {

            return CommonResult.success(algInfoService.getTop5GpuClusterInfo());

        } catch (Exception e) {

            LOGGER.error("CnapClusterInfoController getTop5GpuClusterInfo error", e);

            return CommonResult.failed(e.getMessage());
        }
    }

    /**
     * 获取应用是否暂停
     *
     * @param k8sClusterName 集群名
     * @param svcId      svcId
     * @return 返回服务的信息
     */
    @ApiOperation(value = "3-25 获取应用是否暂停", httpMethod = "GET",
            notes = "入参，集群的名称k8sClusterName，svcId")
    @RequestMapping(path = "/svcIsSuspend", method = RequestMethod.GET)
    public CommonResult<Boolean> svcIsSuspend(String k8sClusterName, String svcId) {

        try {


            K8sClusterBasicModel k8sClusterBasicModel = multiCloudMgmtService.getK8sClusterInfoByName(k8sClusterName);

            return CommonResult.success(k8sClusterService.checkSvcSuspend(k8sClusterBasicModel,svcId));

        } catch (Exception e) {

            LOGGER.error("CnapClusterInfoController svcIsSuspend error svcId={}", svcId, e);

            return CommonResult.failed(e.getMessage());
        }
    }

    @ApiOperation(value = "3-26 获取账户对应的节点数量", httpMethod = "POST",
            notes = "")
    @RequestMapping(path = "/getAccountNodeNum", method = RequestMethod.POST)
    public CommonResult<Map<String,Integer>> getAccountNodeNum(@RequestBody List<AccountNameReqModel> accountNameReqModels) {

        try {

            Map<String,Integer> result = new HashMap<>();
            if ((accountNameReqModels == null)
                    || (accountNameReqModels.isEmpty())) {
                return CommonResult.success(result);
            }

            //获取集群的相关信息
            return CommonResult.success(algInfoService.getAccountNodeNum(accountNameReqModels));

        } catch (Exception e) {

            LOGGER.error("CnapClusterInfoController getAccountNodeNum error", e);

            return CommonResult.failed(e.getMessage());
        }
    }

}
